import { BuilderOptions } from '../entity/builder-options';
import { FarrisDesignBaseComponent } from './component';
import { ComponentSchema } from '../entity/builder-schema';
import { remove, uniqBy } from 'lodash-es';
import { BuilderHTMLElement } from '../entity/builder-element';
import { Observable, of } from 'rxjs';

/**
 * 嵌套类组件基类
 */
export class FarrisDesignBaseNestedComponent extends FarrisDesignBaseComponent {

    /** 组件实例集合 */
    public components: any[];

    /** 容器类组件中需要定义ref="nestedKey"的DOM层级，用来挂载子级组件 */
    get nestedKey() {
        return `nested-${this.key}`;
    }

    /** 获取子级JSON  */
    getComponentContents(): ComponentSchema[] {
        return this.component.contents || [];
    }

    getTemplateName(): string {
        return 'container';
    }


    getDefaultSchema() {
        return FarrisDesignBaseNestedComponent.schema();
    }

    getSchema() {
        // const schema = omit(this.component, ['key']);
        const schema = this.component;
        const components = uniqBy(this.getComponents(), 'component.id');
        schema.contents = [];
        components.forEach(c => {
            schema.contents.push(c.getSchema());
        });
        return schema;
    }


    constructor(component: any, options: any) {
        super(component, options);
    }

    init() {
        this.components = this.components || [];
        this.addComponents();
        return super.init();
    }

    /**
     * Perform an iteration over each component within this container component.
     *
     * @param   fn - Called for each component
     */
    eachComponent(fn) {
        this.getComponents().forEach((component, index) => {
            if (fn(component, index) === false) {
                return false;
            }
        });
    }

    hideNestedPaddingInDesginerView() {
        return false;
    }
    getClassName(): string {

        const className: string = super.getClassName() || '';

        // 容器类组件增加间距
        const hidePadding = this.hideNestedPaddingInDesginerView();

        return hidePadding ? className : className + ' farris-nested';
    }
    /**
     * 向组件中添加子组件
     * @param options 配置数据
     */
    addComponents(options?: BuilderOptions) {
        // data = data || this.data;
        options = options || this.options;

        const componentSchemas = this.hook('addComponents', this.getComponentContents(), this) || [];
        // 迭代添加组件
        componentSchemas.forEach((componentSchema) => this.addComponent(componentSchema, false));

    }

    /**
     *  添加组件
     */
    addComponent(componentSchema: ComponentSchema, noAdd: boolean) {
        componentSchema = this.hook('addComponent', componentSchema, noAdd);
        // 创建组件
        this.createComponent(componentSchema, this.options);
    }

    /**
     * 创建子组件并添加到组件集合中
     * @param componentSchema JSON schema
     * @param options 配置数据
     */
    createComponent(componentSchema: ComponentSchema, options: BuilderOptions, componentId?: string, viewModelId?: string): any {
        if (!componentSchema) {
            return;
        }
        options = options || this.options;
        options.parent = this;
        options.skipInit = true;
        const comp = this.createUiComponent(componentSchema, options);

        // 存储组件所属视图模型id和组件id
        comp.componentId = componentId || this.componentId;
        comp.viewModelId = viewModelId || this.viewModelId;

        comp.init();

        this.components.push(comp);

        return comp;
    }
    /**
     * 创建组件，统一调用父级（Webform类）的创建方法
     * @param componentSchema 控件JSON 结构
     * @param options 配置参数
     */
    createUiComponent(componentSchema: any, options: any) {
        if (this.parent) {
            return this.parent.createUiComponent(componentSchema, options);
        }
        return new FarrisDesignBaseComponent(componentSchema, options);
    }
    getComponents() {
        return this.components || [];
    }

    render(children: string) {
        // If already rendering, don't re-render.
        if (children !== undefined) {
            return super.render(children);
        } else {
            const result = this.renderTemplate(this.getTemplateName(), {
                children: this.renderComponents(),
                nestedKey: this.nestedKey,
                collapsed: false,
            });
            return super.render(result);
        }

    }
    /**
     * 渲染子组件
     * @param  components 子组件实例列表
     * @returns 模板字符串
     */
    renderComponents(components?: any[]) {
        // 确定子组件列表
        components = components || this.getComponents();
        // 渲染子组件获得渲染结果
        const children = components.map(component => component.render());
        // 渲染组件集合模板
        return this.renderTemplate('components', {
            children,
            components,
        });
    }

    destroy() {
        this.destroyComponents();
        super.destroy();
    }

    destroyComponents() {
        const components = this.getComponents().slice();
        components.forEach((comp) => this.removeComponent(comp, this.components));
        this.components = [];
    }
    /**
     * Remove a component from the components array.
     *
     * @param component - The component to remove from the components.
     * @param components - An array of components to remove this component from.
     */
    removeComponent(component: any, components: any) {
        components = components || this.components;
        component.destroy();
        remove(components, { id: component.id });
    }


    attach(element: HTMLElement): Promise<any> {
        const superPromise = super.attach(element);

        // 定位nestedKey指定的DOM元素，然后挂载子级组件
        this.loadRefs(element, {
            [this.nestedKey]: 'single',
        });

        let childPromise = Promise.resolve();
        if (this.refs[this.nestedKey]) {
            childPromise = this.attachComponents(this.refs[this.nestedKey]);
        }
        this.bindingScrollEvent(element);

        return Promise.all([
            superPromise,
            childPromise,
        ]);
    }



    /**
     * 添加组件集合
     * @param element html dom
     */
    attachComponents(element: HTMLElement, components?: any[], container?: any): Promise<any> {
        components = components || this.components;
        const childrenContents = container || this.component.contents;

        // 获取element下的子组件节点集合，即ref='component'的节点
        const childrenElements = this.hook('attachComponents', element, components, childrenContents, this);
        if (!childrenElements || !childrenElements.length) {
            // return (new Promise(() => { }));
            return Promise.resolve()
        }

        let index = 0;
        const promises: Promise<any>[] = [];
        Array.prototype.slice.call(childrenElements).forEach(child => {
            if (!components) {
                return;
            }
            // 鼠标滑过时显示的右上角按钮容器（component-btn-group）有data-noattach标识
            if (!child.getAttribute('data-noattach') && components[index]) {
                promises.push(components[index].attach(child));
                index++;
            }
        });
        return Promise.all(promises);
    }

    get ready(): Promise<any> {
        return Promise.all(this.getComponents().map(component => component.ready));
    }

    clear() {
        if (this.components) {
            this.components.forEach(component => {
                component.clear();
            });
        }

        super.clear();
    }

    detach() {
        if (this.components) {
            this.components.forEach(component => {
                component.detach();
            });
        }

        super.detach();
    }

    /**
     * 判断是否可以接收拖拽新增的子级控件
     * @param data 新控件的类型、所属分类
     * @returns boolean
     */
    canAccepts(sourceElement: BuilderHTMLElement, targetElement?: BuilderHTMLElement, sourceContainer?: BuilderHTMLElement) {
        return false;
    }

    /**
     * 当前容器接收新创建的子控件
     * @param el 移动的源DOM结构
     */
    onAcceptNewChildElement(el: BuilderHTMLElement, targetPosition: number): Observable<any> {
        const serviceHost = this.options.designerHost;
        if (serviceHost) {
            const dragResolveService = serviceHost.getService('DragResolveService');
            if (dragResolveService) {
                return dragResolveService.resolveComponentCreationContextByDrop(el, this, targetPosition);
            }
        }
        return of(null);
    }

    /**
     * 当前容器接收新创建的子控件后事件，用于rebuild之前
     * @param componentResolveContext 控件构造信息
     */
    afterAcceptNewChildElement(componentResolveContext: any) {

    }
    /**
     * 移动内部控件后事件：在可视化设计器中，容器接收控件后事件
     * @param el 移动的源DOM结构
     */
    onAcceptMovedChildElement(el: HTMLElement, soureElement?: HTMLElement) {

    }
    /**
     * 插入的ComponentSchema结构
     * @param componentSchema ComponentSchema
     */
    onAddNewChildElement(componentSchema: ComponentSchema): number {
        return -1;
    }
    /**
     * 移动内部控件后事件：在可视化设计器中，将现有的控件移动到容器中
     * @param el 移动的源DOM结构
     */
    onChildElementMovedOut(el: HTMLElement) {

    }
    /**
     * 删除组件的回调方法
     */
    onRemoveComponent() {
        if (this.components) {
            this.components.forEach(component => {
                if (component.onRemoveComponent) {
                    component.onRemoveComponent();
                }
            });
        }

    }
}
